Aqua Platform EnterpriseをECS-Fargate環境にデプロイしてランタイム検知してみた

Aqua Platform EnterpriseをECS-Fargate環境にデプロイしてランタイム検知してみた

Clock Icon2022.04.27

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは!AWS事業本部コンサルティング部のたかくに(@takakuni_)です。

今回は、ECS-Fargate環境にAqua Platform Enterpriseの「MicroEnforcer」をデプロイしコンテナのランタイム検知を実行してみようと思います。

Aqua Platform Enterpriseとは

Aqua Platformはaqua社が提供するソリューションの1つでコンテナとクラウドネイティブアプリのために開発された、フルライフサイクルなセキュリティソリューションになります。

https://dev.classmethod.jp/articles/about-aqua-csp/

MicroEnforcerとは

Aqua MicroEnforcerは、AWS Fargateのような**Containers-as-a-Service(CaaS)**環境で動作するコンテナにランタイムセキュリティを提供する機能です。

AWS Fargateでは、Amazon ECS on EC2に比べEC2のスケーリング、パッチ当てなどのホストの管理が不要になり、コンテナ開発により集中できるメリットがあります。

一方で、ホストの管理をAWSに任せているため、Enforcerとして一般的に使用する、「Aqua Enforcer」をデプロイできない制約などが存在します。

そのため、Aqua Securityでは、CaaS環境でEnforcerを使用するためのMicroEnforcerを提供しています。

デプロイ方法

MicroEnforcerをデプロイする方法は以下の2種類があります。

  1. アプリケーションコンテナのDockerfile内にMicroEnforcerのバイナリを埋め込み立ち上げる方法
  2. サイドカーコンテナからアプリケーションコンテナへMicroEnforcerの情報を渡しコンテナを立ち上げる方法

今回は、1の方法を採用してMicroEnforcerをデプロイしようと思います。

構成図

構成図は以下の通りです。

  1. サブネットを除く赤枠のリソースをCloudFormationで作成します。
  2. 各コンテナは以下のエンドポイントに到達する必要があるためNAT Gatewayを使用します。(VPC EndpointやInternal LoadBalancerを使用することでインターネットを経由しない構成も可能です。)
  • Application Container:ECR、NLB
  • Aqua Gateway:ECR
  • Aqua Console:ECR、Secrets Manager
  1. Aqua Databaseは、CloudFormationのパラメターでマルチAZ可能になっていますが今回はシングルAZで実装します。
  2. 今回、ALB用に証明書をACMから発行しましたが発行しなくても実装は可能です。

検証用VPCの作成

すでに使用したいVPCが決まっていれば、この手順は飛ばしてもらって構いません。

構成図の通り、2AZ間でパブリック/プライベートサブネットを作成し、1つのAZでNAT Gatewayを作成する構成を作成しました。

図で表すと以下のリソースまで作成できました。

ECRの作成

ECSでコンテナを起動するためDocker Imageを保存するレジストリを作成します。

今回作成するレジストリは以下の3つです。

  • aqua-console(Aqua ServerのDocker Image用)
  • aqua-gateway(Aqua GatewayのDocker Image用)
  • aqua-container(Application ContainerのDocker Image用)

同じように残り2つのレジストリも作成します。

イメージのプッシュ(Aqua Server/Gateway)

作業手順は以下の通りです。

  1. Dockerイメージの取得を行うためAquaにログインします。
  2. docker image pullでイメージを取得します。
  3. ECRへログイン
  4. docker image tagでイメージにタグ付けを行います。
  5. docker image pushでイメージをECRにプッシュします。

# 1. Dockerイメージの取得を行うためAquaにログインします。
takakuni@~ % docker login registry.aquasec.com 
Username: XXXXXXXXXXXX@example.com
Password: 

Login Succeeded

# 2. `docker image pull`でイメージを取得します。
# aqua-console
takakuni@~ % docker pull registry.aquasec.com/console:6.5

# aqua-gateway
takakuni@~ % docker pull registry.aquasec.com/gateway:6.5

# 3. ECRへログイン(XXXXXXXXXXXXはアカウントID, リージョンも気をつけるポイント)

takakuni@~ % aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com

# 4. `docker image tag`でイメージにタグ付けを行います。
# aqua-console
takakuni@~ % docker image tag registry.aquasec.com/console:6.5 XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/aqua-console:latest

# aqua-gateway
takakuni@~ % docker image tag registry.aquasec.com/gateway:6.5 XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/aqua-gateway:latest

# 5. `docker image push`でイメージをECRにプッシュします。

# aqua-console
takakuni@~ % docker push XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/aqua-console:latest

# aqua-gateway
takakuni@~ % docker push XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/aqua-gateway:latest

図にすると以下のリソースまで作成できている状態になります。

CloudFormationの実行

以下のリポジトリからCloudFormationスタックの作成を行います。

今回使用するブランチは、「6.5」を使用しますが必要に応じてバージョンアップしたブランチをご使用ください。

https://github.com/aquasecurity/deployments/tree/6.5/server/ecs/cloudformation/aqua-ecs-fargate

今回はaquaFargate.yamlを使用してデプロイします。イベント履歴を確認すると作成には15分程度要していました。

使用するパラメータの例は以下の通りです。

キー 備考
ActiveActive false
AquaConsoleAccess 0.0.0.0/0
AquaGatewayImage XXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/aqua-gateway
AquaServerImage XXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/aqua-console
AuditRDS No
AuditRdsInstanceClass db.t3.medium
ClusterName aqua-enterprise 任意の値
EcsInstanceSubnets 2AZにまたがるプライベートサブネットを2つ選択
LBScheme internet-facing
LbSubnets 2AZにまたがるパブリックサブネットを2つ選択
MultiAzDatabase false
RdsInstanceClass db.t3.medium
RdsStorage 50
SSLCert ALBに紐づけるACMのARN
VpcCidr 10.0.0.0/16
VpcId デプロイするVPCのID

図にすると以下のリソースまで作成できている状態になります。

ALBのレコード登録

ACMにて証明書をリスナーに設定したので、設定したドメインでログインできるようにRoute53またはDNSサーバーのレコードを登録します。

私の場合は、Route53でドメインを管理しているため以下のエイリアスレコードを登録しました。

キー 備考
レコード名 ACMと同じドメイン
レコードタイプ Aレコード
エイリアス 有効 Route53でのみ使用可能
Application LoadBalancerのエイリアス ALBのDNS名

Aqua Consoleへのログイン

Route53にレコード登録したドメインを経由で、ALBへログインを行います。

今回は検証のため以下のユーザーとパスワードで登録します。

キー 備考
ユーザー名 administrator
パスワード Admin1qaz@wsx

問題なければライセンスの登録を行います。ライセンスの登録が完了したら、コンソール画面へ遷移します。

Enforcer Groupの作成

画面左ペインの「Administration」をクリックして、「Enforcers」をクリックします。

「Add Enforcer Group」をクリックして今回使用するMicroEnforcerのグループを作成します。

使用したパラメータは以下の通りです。

キー 備考
Enforcer Type Aqua MicroEnforcer
Group Name ECS-FargateMicroEnforcerGroup
Logical Name ECS-FargateMicroEnforcerLGroup
Aqua Gateway デフォルトの値(ip-10-0-135-9.ap-northeast-1.compute.internalなどの値)
Deployment Token ECS-FargateMicroEnforcerDeploymentToken

加えて、検知した際の挙動をブロックしたいため「Advanced settings」から「Enforcement Mode」を「Enforce」に変更します。

「Create Group」をクリックすると、Enforcer Groupが作成されます。

「Group Name」と「Logical Name」の違い

設定値でNameを設定する箇所が2箇所あり何が違うのかをざっくり説明します。

Group Name

Aquaコンソールから確認できる「Enforcer Group」の名前に当たります。

設定後は変更できないため命名には注意が必要です。

Logical Name

MicroEnforcerから確認するための「Enforcer Group」の名前に当たります。

主にMicroEnforcerを組み込むDockerコンテナの環境変数に指定します。設定後でも名前を変更できます。

また、Group NameとLogical Nameは1対1で紐づいており、複数のLogical Nameを紐づけることができないことも注意が必要です。

Application Containerの作成

Dockerfileの作成

今回は、アプリケーションコンテナとしてnginxを立ち上げたいためdocker image pullでイメージを取得します。

takakuni@~ % docker image pull --platform x86_64 nginx:1.21.6

また、本記事では起動するコンテナにMicroEnforcerを仕込み制御を行うため、Dockerfileを作成し、MicroEnforcerの組み込みを定義します。

作成するDockerfileに必要な情報は以下の通りです。

  1. MicroEnforcerバイナリ
  2. DockerイメージのCMD, ENTRYPOINTの値

MicroEnforcerバイナリの取得

以下、URLへアクセスし「ユーザー名」、「パスワード」を入力後、ダウンロードを行います。

https://download.aquasec.com/micro-enforcer/6.5.0/microenforcer

CMD, ENTRYPOINTの取得

Dockerイメージで設定されたCMD,ENTRYPOINTの値を探します。

取得したnginxイメージに対して以下のコマンドを入力します。

takakuni@~ % docker image inspect nginx:1.21.6 -f "{{json .Config.Cmd}}"

# 期待値:["nginx","-g","daemon off;"]

takakuni@~ % docker image inspect nginx:1.21.6 -f "{{json .Config.Entrypoint}}"

# 期待値:["/docker-entrypoint.sh"]

Dockerfileのでき上がり例

仕上がり例としては以下のようなYAMLファイルになります。

Dockerfiile
FROM nginx:1.21

# ダウンロードしたmicroenforcerを追加
ADD microenforcer /bin/microenforcer
RUN ["chmod", "+x", "/bin/microenforcer"]
RUN ["/bin/microenforcer", "aqua-init"]

# 取得した値を記載
CMD ["nginx","-g","daemon off;"]
ENTRYPOINT ["/bin/microenforcer","/docker-entrypoint.sh"]

ビルド

以下のコマンドでDockerイメージのビルド、ECRへのプッシュを行います。

# ECRへログイン
takakuni@~ % aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com
# イメージのビルド
takakuni@~ % docker image build --platform x86_64 -t aqua-container .
# タグ付け
takakuni@~ % docker image tag aqua-container:latest XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/aqua-container:latest
# プッシュ
takakuni@~ % docker image push XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/aqua-container:latest

タスク定義の作成

実際にコンテナを起動するためにタスクを定義します。

タスク定義では、以下の環境変数を起動するコンテナに渡し、MicroEnforcerとAqua Gatewayを通信できるように設定します。

  • AQUA_TOKEN:MicroEnforcerとEnforcerグループ間で認証するためのトークン
  • AQUA_SERVER:Aqua GatewayのIPアドレス:8443またはNLBのDNS名:8444
  • AQUA_LOGICAL_NAME:Enforcerグループで指定したLogical Name

なお、上記の環境変数はEnforcerグループの管理画面より確認できます。

AQUA_SERVERの設定値について

AQUA_SERVERの設定値についてですが以下の2種類の方法が考えられます。

  • Aqua GatewayのIPアドレスにPort:8443で直接アクセス
  • NLBのDNS名に対してPort:8444でアクセス

Aqua Gatewayが何かしらの原因で落ちてしまった際に共倒れを防ぐため今回は、NLBのDNSに対してPort:8444で設定を行います。

「環境、ストレージ、モニタリング、タグの設定」では、IAMロールを「ecsTaskExecution」に変更し次に進みます。

確認画面の結果も念の為載せておきます。問題なければ「作成」をクリックします。

セキュリティグループの作成

サービスを立ち上げるため、アプリケーションコンテナ用にセキュリティグループを設定します。

今回は、タスク定義でマッピングした80番ポートを開くように設定しました。

サービスの起動

必要な情報が揃ったので実際にサービスを起動します。

注意が必要なポイントは以下になります。

  • 「リビジョン」は意図したバージョン(最新など)ですか
  • 「サブネット」はプライベートサブネットを選択
  • 「セキュリティグループ」はさきほど作成したものを選択
  • パブリックIPはNAT Gatewayを経由するため必要なし

サービスの起動が完了すると以下、Enforcer管理画面からコンテナがグループに登録されていることを確認できます。

以上でMicroEnforcerの設定は完了しました。

ランタイム検知(動作確認)

Runtime policyの編集

動作確認のため、「Drift Prevention」を使用して、元のコンテナイメージにないファイルの実行が防止されるか確認してみます。

Aqua Consoleから「Policy」、「Runtime Policies」を選択します。

「Aqua default runtime policy」を選択して編集します。

「Enforcement Mode」を「Enforce」にして「Save」をクリックします。

再起動を求められる画面で、「OK」を選択します。

ECS Execの有効化

今回はESC ExecからRuntime検知を行うため有効化設定を行います。

初めに、IAMロール「ecsTaskExecution」に以下のポリシーをインラインまたはIAMポリシーを新規作成してアタッチします。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ssmmessages:CreateControlChannel",
                "ssmmessages:CreateDataChannel",
                "ssmmessages:OpenControlChannel",
                "ssmmessages:OpenDataChannel"
            ],
            "Resource": "*"
        }
    ]
}

AWS CLIで「ECS Execの有効化」を行います。

今回は、以下ブログを参考にしました。

https://dev.classmethod.jp/articles/ecs-exec-for-fish-shell/

# 環境変数定義
CLUSTERNAME=$(aws ecs list-clusters --query 'clusterArns[0]' --output text)
SERVICENAME=$(aws ecs list-services --cluster $CLUSTERNAME --query 'serviceArns[-1]' --output text)
TASKNAME=$(aws ecs list-tasks --cluster $CLUSTERNAME --service-name $SERVICENAME --query "taskArns[0]" --output text)
CONTAINERNAME=$(aws ecs describe-tasks --cluster $CLUSTERNAME --tasks $TASKNAME --query "tasks[].containers[].name" --output text)

# ECS Exec有効化
aws ecs update-service --cluster $CLUSTERNAME --service $SERVICENAME --enable-execute-command | grep enableExecuteCommand

# ECS Exec有効化したタスクを実行
aws ecs update-service --cluster $CLUSTERNAME --service $SERVICENAME --task-definition "aqua-container" --force-new-deployment

# 環境変数更新
TASKNAME=$(aws ecs list-tasks --cluster $CLUSTERNAME --service-name $SERVICENAME --query "taskArns[0]" --output text)

# ECS Execでコンテナに接続
aws ecs execute-command --cluster $CLUSTERNAME --task $TASKNAME --container $CONTAINERNAME --interactive --command "/bin/sh"

ECS Execでログイン後、「Drift Prevention」が効いていることを確認できました。

takakuni@~ % aws ecs execute-command --cluster $CLUSTERNAME --task $TASKNAME --container $CONTAINERNAME --interactive --command "/bin/sh"

The Session Manager plugin was installed successfully. Use the AWS CLI to start a session.

Starting session with SessionId: ecs-execute-command-XXXXXXXXXXXXXXXXX
# cp -p /bin/pwd /bin/pod
# pod
Permission denied

参考

https://aws.amazon.com/jp/blogs/apn/deploying-devsecops-on-amazon-eks-with-aqua-security-part-2/

https://www.creationline.com/lab/aquasecurity/45749

https://dev.classmethod.jp/articles/ecs-exec-for-fish-shell/

まとめ

以上、「Aqua Platform EnterpriseをECS-Fargate環境にデプロイしてランタイム検知してみた」でした。

CaaS環境でもコンテナセキュリティを実装したいとご検討のお客様はぜひAqua Enterpriseも選択肢の1つとしてご検討いただけますと幸いです。

以上、AWS事業本部コンサルティング部のたかくに(@takakuni_)でした!

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.